package com.xiangban.service;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiangban.exception.BizException;
import com.xiangban.dao.UserBaseMapper;
import com.xiangban.model.TSystem;
import com.xiangban.model.TUserBase;
import com.xiangban.model.dto.*;
import com.xiangban.model.res.ApiResult;
import com.xiangban.model.res.ApiResultCode;
import com.xiangban.service.UserBaseService;
import com.xiangban.service.fegin.SystemServiceFeign;
import com.xiangban.service.fegin.XiangBanMallServiceFeign;
import com.xiangban.service.fegin.XiangDoctorServiceFeign;
import com.xiangban.service.fegin.YangLaoDaJieServiceFeign;
import com.xiangban.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.spring.web.json.Json;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.xiangban.utils.CommonUtil.*;
import static com.xiangban.utils.HttpClientUtil.*;
import static com.xiangban.utils.RedisUtil.*;

@Service
@Slf4j
public class UserBaseServiceImpl implements UserBaseService {
    public final  static String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    @Value("${system.yanglaodajie_access_id}")
    private String yanglaodajie_access_id;

    @Value("${system.xiangbanmall_access_id}")
    private String xiangbanmall_access_id;

    @Value("${system.xiangcheng_access_id}")
    private String xiangcheng_access_id;

    @Value("${system.xiangbandoctor_access_id}")
    private String xiangbandoctor_access_id;

    @Value("${system.xiangbandoctor_accompany_access_id}")
    private String xiangbandoctor_accompany_access_id;


    @Autowired
    private CommonUtil commonUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserBaseMapper userBaseMapper;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private SystemServiceFeign systemServiceFeign;

    @Autowired
    private XiangBanMallServiceFeign xiangBanMallServiceFeign;

    @Autowired
    private YangLaoDaJieServiceFeign yangLaoDaJieServiceFeign;

    @Autowired
    private XiangDoctorServiceFeign xiangDoctorServiceFeign;

    @Transactional
    public void register(RegisterDto registerDto) {

        if (common_1.equals(registerDto.getType())) { //普通注册
            //非空判断
            if (BizEmpty(registerDto.getVerification())) {
                throw new BizException(ApiResultCode.NULL_VERIFICATION);
            }
            if (BizEmpty(registerDto.getAccount())) {
                throw new BizException(ApiResultCode.NULL_ACCOUNT);
            }
            if (BizEmpty(registerDto.getPassword())) {
                throw new BizException(ApiResultCode.NULL_PASSWORD);
            }
            if (BizEmpty(registerDto.getPhone())) {
                throw new BizException(ApiResultCode.NULL_PHONE);
            }
            //校验验证码
            if (checkCode(RegisterDto.verification_type_register, registerDto.getPhone(), registerDto.getVerification())) {
                throw new BizException(ApiResultCode.FAILED_VERIFICATION);
            }
            //检查用户是否注册
            if (!BizEmpty(checkerAccount(registerDto))) {
                throw new BizException(ApiResultCode.EXIST_ACCOUNT);
            } else if (!BizEmpty(checkerPhone(registerDto))) {
                throw new BizException(ApiResultCode.EXIST_PHONE);
            }

            registerDto.setPassword(Md5Utils.hash(registerDto.getPassword()));
            registerDto.setStatus(0);
            registerDto.setStatus(0);
            if("0".equals(registerDto.getSex())){
                registerDto.setSex("1");
            }
            userBaseMapper.register(registerDto);
            //同步子系统
            registerUser(registerDto);

        } else if (common_2.equals(registerDto.getType())) {//快捷注册

            if (BizEmpty(registerDto.getCertificate())) {
                throw new BizException(ApiResultCode.NULL_CERTIFICATE);
            }
            String phone = redisUtil.get(fex_certificate + registerDto.getCertificate());
            if (BizEmpty(phone)) {
                throw new BizException(ApiResultCode.ERROR_CERTIFICATE);
            }
            String randomString = getRandomString(8);
            registerDto.setAccount(randomString);
            registerDto.setPhone(phone);
            //检查用户是否注册
            if (!BizEmpty(checkerAccount(registerDto))) {
                throw new BizException(ApiResultCode.EXIST_ACCOUNT);
            } else if (!BizEmpty(checkerPhone(registerDto))) {
                throw new BizException(ApiResultCode.EXIST_PHONE);
            }
            registerDto.setPassword(Md5Utils.hash(registerDto.getPassword()));
            registerDto.setStatus(0);
            userBaseMapper.register(registerDto);
            //失效凭证
            invalidCertificate(registerDto.getCertificate(), phone);
            //同步子系统
            registerUser(registerDto);
        }
    }

    @Override
    public Map<String, String> login(LoginDto loginDto) {
        HashMap<String, String> res = new HashMap<>();
        //判断登录类型
        if (common_1.equals(loginDto.getType())) { //验证码登陆
            //校验验证码
            if (checkCode(RegisterDto.verification_type_login, loginDto.getPhone(), loginDto.getVerification())) {
                throw new BizException(ApiResultCode.FAILED_VERIFICATION);
            }
            //验证手机
            RegisterDto registerDto = new RegisterDto();
            registerDto.setPhone(loginDto.getPhone());
            TUserBase tUserBase = checkerPhone(registerDto);
            if (!BizEmpty(tUserBase)) { //已注册 登陆
                //生成token
                String token = generateToken(tUserBase.getUid());
                res.put("token", token);
            } else {
                //未注册
                String certificate = generateCertificate(loginDto.getPhone());
                res.put("certificate", certificate);
            }
            commonUtil.invalidVerification(RegisterDto.verification_type_login, loginDto.getPhone());


        } else if (common_2.equals(loginDto.getType())) { //账号/手机号 密码登录
            String account = loginDto.getAccount();
            TUserBase userBase = new TUserBase();
            userBase.setAccount(account);
            TUserBase userInfo = userBaseMapper.getUserBaseInfo(userBase);
            if (BizEmpty(userInfo)) {
                throw new BizException(ApiResultCode.FAILED_ACCOUNT);
            }
            if (!compare(Md5Utils.hash(loginDto.getPassword()+""), userInfo.getPassword())) {
                throw new BizException(ApiResultCode.FAILED_LOGIN);
            }
            //生成token
            String token = generateToken(userInfo.getUid());
            res.put("token", token);
        } else if (common_3.equals(loginDto.getType())) { //微信登录
            String sessionKey = loginDto.getSessionKey();
            if (BizEmpty(sessionKey)) {
                throw new BizException(ApiResultCode.NULL_SESSION_KEY);
            }
            //获取用手机号信息
            JSONObject userInfo = WeChatUtil.getUserInfo(loginDto.getEncryptedData(),
                    sessionKey, loginDto.getIv());
            if (BizEmpty(userInfo)) {
                //手机号解析失败
                throw new BizException(ApiResultCode.NULL_USER_INFO);
            }
            String phone = (String) userInfo.getObj("phoneNumber");
            if (BizEmpty(phone)) {
                //手机号解析失败
                throw new BizException(ApiResultCode.NULL_PHONE);
            }
            String openId = commonUtil.getOpenId(sessionKey); //微信openId
            RegisterDto registerDto = new RegisterDto();
            registerDto.setWxOpenId(openId);
            registerDto.setPhone(phone);
            registerDto.setStatus(0);
            registerDto.setSex(loginDto.getSex());
            registerDto.setNickName(loginDto.getNickName());
            registerDto.setImage(loginDto.getImage());
            String randomString = getRandomString(8);
            registerDto.setAccount(randomString);
            //判断用户是否已经注册
            TUserBase tUserBaseRes = checkerPhone(registerDto);
            HashMap<String, Object> parameter = new HashMap<>();
            parameter.put("openId",openId);
            parameter.put("phone",phone);
            parameter.put("accessId",loginDto.getAccessId());
            if (!BizEmpty(tUserBaseRes)) { //已注册 登陆
                //生成token
                String token = generateToken(tUserBaseRes.getUid());
                res.put("token", token);
                parameter.put("uid",tUserBaseRes.getUid());

            } else {
                //未注册
                userBaseMapper.register(registerDto);
                //同步子系统
                registerUser(registerDto);
                String token = generateToken(registerDto.getUid());
                res.put("token", token);
                res.put("phone", phone);
                parameter.put("uid",registerDto.getUid());
            }
            log.info("开始同步openId");
            if (yanglaodajie_access_id.equals(loginDto.getAccessId())){
                ApiResult<Object> objectApiResult = yangLaoDaJieServiceFeign.updateUserOpenId(parameter);
                log.info(JSON.toJSONString(objectApiResult));
            }else if (xiangbanmall_access_id.equals(loginDto.getAccessId())){
                ApiResult<Object> objectApiResult = xiangBanMallServiceFeign.updateUserOpenId(parameter);
                log.info(JSON.toJSONString(objectApiResult));
            }else if (xiangcheng_access_id.equals(loginDto.getAccessId())){
                ApiResult<Object> objectApiResult = yangLaoDaJieServiceFeign.updateUserOpenId(parameter);
                log.info(JSON.toJSONString(objectApiResult));
            }else if (xiangbandoctor_access_id.equals(loginDto.getAccessId()) || xiangbandoctor_accompany_access_id.equals(loginDto.getAccessId())){
                ApiResult<Object> objectApiResult = xiangDoctorServiceFeign.updateUserOpenId(parameter);
                log.info(JSON.toJSONString(objectApiResult));
            }


        } else {
            throw new BizException(ApiResultCode.NULL_LOGIN_TYPE);
        }
        return res;

    }

    /**
     * 失效凭证
     *
     * @param certificate 凭证
     */
    public void invalidCertificate(String certificate, String phone) {
        redisUtil.del(fex_certificate + phone, fex_certificate + certificate);
    }

    public String generateToken(Integer uid) {
        String newToken = UUID.randomUUID().toString().replace("-", "");
        HashMap<String, Object> loginInfo = new HashMap<>();
        loginInfo.put("time", new Date().getTime());
        loginInfo.put("uid", uid);
        //获取上次token
        String oldToken = redisUtil.get(fex + uid);
        //清除上次登录token
        redisUtil.del(fex + oldToken, fex + uid);
        redisUtil.set(fex + uid, newToken, tokenTime);
        redisUtil.set(fex + newToken, JSON.toJSONString(loginInfo), tokenTime);
        return newToken;
    }

    //凭证生成
    public String generateCertificate(String phone) {
        String certificate = UUID.randomUUID().toString().replace("-", "");

        //获取上次token
        String oldCertificate = redisUtil.get(fex_certificate + phone);
        //清除上次登录token
        redisUtil.del(fex_certificate + oldCertificate, fex_certificate + phone);
        redisUtil.set(fex_certificate + phone, certificate, codeTime);
        redisUtil.set(fex_certificate + certificate, phone, codeTime);
        return certificate;
    }


    public boolean checkCode(String verification_type, String phone, String code) {
        String code1 = redisUtil.get(verification_type + phone);
        return !code.equals(code1);
    }

    public TUserBase checkerAccount(RegisterDto registerDto) {
        //验证账号
        RegisterDto registerDtoAccount = new RegisterDto();
        registerDtoAccount.setAccount(registerDto.getAccount());
        registerDtoAccount.setStatus(0);
        return userBaseMapper.checkUser(registerDtoAccount);

    }

    public TUserBase checkerPhone(RegisterDto registerDto) {
        //验证手机
        RegisterDto registerDtoPhone = new RegisterDto();
        registerDtoPhone.setPhone(registerDto.getPhone());
        registerDtoPhone.setStatus(0);
        return userBaseMapper.checkUser(registerDtoPhone);

    }

    @Override
    public HashMap<String, Object> getSessionKey(WeChatUserInfoDto weChatUserInfoDto) {
        HashMap<String, Object> res = new HashMap<>();

        //.获取小程序appId，小程序secret
        TSystem tSystem = new TSystem();
        tSystem.setAccessId(weChatUserInfoDto.getAccessId());
        ApiResult<TSystem> objectApiResult = systemServiceFeign.selectSystemByAccessId(tSystem);
        if (objectApiResult.isSuccess()){
            Object dataMap = objectApiResult.getDataMap();
            if (dataMap != null){

                ObjectMapper objectMapper = new ObjectMapper();
                Map system = objectMapper.convertValue(dataMap, Map.class);
//                Map<String,Object> system = (HashMap<String,Object>)dataMap;
                // 2.开发者服务器 登录凭证校验接口 appId + appSecret + 接收小程序发送的code
                JSONObject SessionKeyOpenId = WeChatUtil.getSessionKeyOrOpenId(weChatUserInfoDto.getCode(),
                        system.get("wxAppletsId").toString(),system.get("wxAppletsSecret").toString());
                String openid = SessionKeyOpenId.get("openid", String.class);
                String sessionKey = SessionKeyOpenId.get("session_key", String.class);
                if (BizEmpty(openid) || BizEmpty(sessionKey)) {
                    throw new BizException(ApiResultCode.PARAMETER_EXCEPTION);
                }
                //存储到redis
                commonUtil.sessionKey(openid, sessionKey);
                JSONObject userInfo = WeChatUtil.getUserInfo(weChatUserInfoDto.getEncryptedData(),
                        sessionKey, weChatUserInfoDto.getIv());
                if (userInfo == null) {
                    throw new BizException(ApiResultCode.SYS_ERROR);
                }
                res.put("sessionKey", sessionKey);

            }
        }
        return res;

    }

    @Override
    public ApiResult<Object> getUserInfo(String token) {
        if (BizEmpty(token)){
            token = request.getHeader("token");

        }
        if (BizEmpty(token)) {
            throw new BizException(ApiResultCode.NULL_TOKEN);
        }
        String userInfo = redisUtil.get(fex + token);
        if (BizEmpty(userInfo)) {
            throw new BizException(ApiResultCode.FAILED_TOKEN);
        }
        com.alibaba.fastjson.JSONObject user = JSON.parseObject(userInfo);
        Integer uid = (Integer) user.get("uid");
        UserDto userDto = new UserDto();
        userDto.setUid(uid);
        userDto.setStatus(0);
        UserDto userInfoRes = userBaseMapper.getUserInfo(userDto);
        return ApiResult.newSuccess(userInfoRes);
    }


    @Override
    public void resetPassword(LoginDto loginDto) {

        if (BizEmpty(loginDto.getPhone())) {
            throw new BizException(ApiResultCode.NULL_PHONE);
        }
        if (BizEmpty(redisUtil.get(RegisterDto.verification_type_rest_password + loginDto.getPhone())) || !loginDto.getVerification().equals(redisUtil.get(RegisterDto.verification_type_rest_password + loginDto.getPhone()))) {
            throw new BizException(ApiResultCode.FAILED_VERIFICATION);
        }
        loginDto.setAccount(loginDto.getPhone());
        TUserBase userBaseInfo = userBaseMapper.getUserBaseInfo(loginDto);
        if (userBaseInfo == null) {
            throw new BizException(ApiResultCode.FAILED_ACCOUNT);
        }
        LoginDto loginDto1 = new LoginDto();
        loginDto1.setPassword(Md5Utils.hash(loginDto.getPassword()));
        loginDto1.setUpdateTime(new Date().toString());
        loginDto1.setPhone(loginDto.getPhone());
        userBaseMapper.updateUserBaseInfo(loginDto1);
        commonUtil.invalidVerification(RegisterDto.verification_type_rest_password, loginDto.getPhone());


    }

    @Override
    public void updateUserInfo(RegisterDto registerDto) {
        if (BizEmpty(registerDto.getUid())){
            throw new BizException(ApiResultCode.NULL_ACCOUNT);
        }
        userBaseMapper.updateUserBaseInfo(registerDto);
    }

    @Override
    public List<TUserBase> getUserList() {
       return userBaseMapper.selectUserBaseList();
    }
/**
 * 获取AccessToken
 * */
    @Override
    public Object getAccessToken(TSystem tSystem) {
//小程序
        String AppletsId = "";
        String AppletsSecret="";
        ApiResult<TSystem> system = systemServiceFeign.selectSystemByAccessId(tSystem);
        TSystem dataMap = system.getDataMap();
        if (dataMap!=null){
            if (tSystem.getType()==1){
                AppletsId = dataMap.getWxAppletsId();
                AppletsSecret = dataMap.getWxAppletsSecret();
            }else if (tSystem.getType()==2){
                AppletsId=  dataMap.getWxEmsCnplId();
                AppletsSecret=  dataMap.getWxEmsCnplSecret();
            }
            String replace = url.replace("APPID", AppletsId).replace("APPSECRET", AppletsSecret);
            String s = HttpClientUtil.doGet(replace);
            log.info("================="+s);
            try {
                Map<String, Object> parse = (Map<String, Object>) JSON.parse(s);
                String access_token = parse.get("access_token").toString();
//                if (dataMap.getSystemName().equals("相伴商城")){
                    redisUtil.set(dataMap.getAccessId(),access_token,7200);
//                }
//                if (dataMap.getSystemName().equals("养老大街")){
//                    redisUtil.set("yanglaodajie_access_token",access_token,7200);
//                    System.out.println("存入");
//                }

                return parse;
            }catch (Exception e){
                throw new BizException("accessId错误");
            }

        }
       throw new BizException("accessId不正确");
    }


    public void registerUser(RegisterDto registerDto){
        //获取系统注册回调
        ApiResult<Object> res = systemServiceFeign.allSystemConfig();
        if (res.isSuccess()){
            Object dataMap = res.getDataMap();
            if (dataMap!=null){
                List<Map<String,String >> systemList = (List<Map<String, String>>) res.getDataMap();
                for (Map<String,String> systemDto : systemList) {
                    String userRegisterUrl = systemDto.get("userRegisterUrl");
                    if (userRegisterUrl!=null){
                        String s = doPostJson(userRegisterUrl, JSON.toJSONString(registerDto));
                        if ("ok".equals(s)){
                            log.info("\n用户：{} \n 状态：成功\n 系统名称：{} \n 系统地址:{}",registerDto.getPhone(),systemDto.get("systemName"),userRegisterUrl);

                        }else {
                            log.info("\n用户：{} \n 状态：失败\n 系统名称：{} \n 系统地址:{}",registerDto.getPhone(),systemDto.get("systemName"),userRegisterUrl);

                        }
                    }else {
                        log.info("系统url为空");
                    }

                }

            }

        }else {
            log.info("获取系统注册回调失败了");
        }
    }

    @Override
    public Object getSignature(TSystem tSystem,String url) {
        String  token = JSON.parseObject(this.getAccessToken(tSystem).toString()).get("access_token").toString();
        String ticket = null;
        String url1 = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token + "&type=jsapi";
        String resp = HttpClientUtil.doGet(url1);
        com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(resp);
        ticket = jsonObject.get("ticket").toString();
//        String url = "http://sts.xbhg365.com/views/health.aspx?type=2";
        long timeStampSec = System.currentTimeMillis() /1000;
        String timestamp = String.format("%010d", timeStampSec);
        String nonceStr = getRandomStr(8);
        String[] urls = url.split("#");
        String newUrl = urls[0];
        JSONObject respJson =new JSONObject();
        String[] signArr =new String[]{"url=" + newUrl,"jsapi_ticket=" + ticket,"noncestr=" + nonceStr,"timestamp=" + timestamp};
        Arrays.sort(signArr);
        String signStr = StringUtils.join(signArr,"&");
        String resSign = DigestUtils.sha1Hex(signStr);
        respJson.put("appId", "wx0f78fda8fadf113b");
        respJson.put("timestamp", timestamp);
        respJson.put("nonceStr", nonceStr);
        respJson.put("signature", resSign);

        return respJson;
    }
    public  String getRandomStr(int length) {
        String base ="fdajfkdajsklfjafdkjxjkljfadnfdnamn12687";
        int randomNum;
        char randomChar;
        Random random =new Random();
        StringBuffer str =new StringBuffer();
        for (int i =0; i < length; i++) {
            randomNum = random.nextInt(base.length());
            randomChar = base.charAt(randomNum);
            str.append(randomChar);
        }
        return str.toString();
    }
}
